package grpcclient

import (
	"context"
	"errors"
	"fmt"
	"sync"
	"time"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"google.golang.org/grpc/keepalive"

	"chat.com/common"
	pb "chat.com/server/grpc/protobuf"
)

var mu sync.RWMutex = sync.RWMutex{}
var clients map[string]*RpcClient = map[string]*RpcClient{}

type RpcClient struct {
	addr       string
	conn       *grpc.ClientConn
	grpcClient pb.AccServerClient
}

func NewRpcClient(addr string) *RpcClient {

	rc := RpcClient{}
	rc.addr = addr
	var err error

	var kacp = keepalive.ClientParameters{
		Time:                10 * time.Minute, // send pings every 10 seconds if there is no activity
		Timeout:             1 * time.Minute,  // wait 1 second for ping ack before considering the connection dead
		PermitWithoutStream: true,             // send pings even without active streams
	}

	rc.conn, err = grpc.Dial(rc.addr, grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithKeepaliveParams(kacp))
	if err != nil {
		fmt.Printf("<rpcclient>can not connect rpcserver addr: %s\n", err)
	}

	rc.grpcClient = pb.NewAccServerClient(rc.conn)

	return &rc
}

// 添加一个新的grpc连接
func AddClient(server string, addr string) {

	mu.Lock()
	defer mu.Unlock()

	client := NewRpcClient(addr)
	clients[server] = client
	fmt.Printf("Add %s -> grpc clients nums: %d\n", server, len(clients))
	fmt.Println("-------------------------------")
}

// 删除一个grpc连接
func RemoveClient(server string) {

	mu.Lock()
	defer mu.Unlock()

	delete(clients, server)
	fmt.Printf("Remove %s -> grpc clients nums: %d\n", server, len(clients))
	fmt.Println("-------------------------------")
}

// rpc client
// 给全体用户发送消息
// link::https://github.com/grpc/grpc-go/blob/master/examples/helloworld/greeter_client/main.go
func SendSystemMsg(server string, appId int64, senderId int64, cmd string,
	message string, sentTime int64) (sendMsgId int64, err error) {

	ctx, cancel := context.WithTimeout(context.Background(), 100*time.Second)
	defer cancel()

	req := pb.SendSystemMsgReq{
		AppId:    appId,
		SenderId: senderId,
		Cms:      cmd,
		Msg:      message,
		SentTime: sentTime,
	}

	mu.RLock()
	rsp, err := clients[server].grpcClient.SendSystemMsg(ctx, &req)
	mu.RUnlock()

	if err != nil {
		fmt.Println("给全体用户发送消息", err)

		return
	}

	if rsp.GetRetCode() != common.OK {
		fmt.Println("给全体用户发送消息", rsp.String())
		err = errors.New(fmt.Sprintf("发送消息失败 code:%d", rsp.GetRetCode()))

		return
	}

	sendMsgId = rsp.GetSendMsgId()
	fmt.Println("给全体用户发送消息 成功:", sendMsgId)

	return
}

// 获取用户列表
func GetUserList(server string, appId int64) (userIds []int64, err error) {

	userIds = make([]int64, 0)

	ctx, cancel := context.WithTimeout(context.Background(), 100*time.Second)
	defer cancel()

	req := pb.GetUserListReq{
		AppId: appId,
	}

	mu.RLock()
	rsp, err := clients[server].grpcClient.GetUserList(ctx, &req)
	mu.RUnlock()

	if err != nil {
		fmt.Println("获取用户列表 发送请求错误:", err)

		return
	}

	if rsp.GetRetCode() != common.OK {
		fmt.Println("获取用户列表 返回码错误:", rsp.String())
		err = errors.New(fmt.Sprintf("发送消息失败 code:%d", rsp.GetRetCode()))

		return
	}

	userIds = rsp.GetUserId()
	fmt.Println("获取用户列表 成功:", userIds)

	return
}

// rpc client 发送单聊消息
func SendSingleChatMsg(server string, msg *common.WsSingleChatRequest) (err error) {
	ctx, cancel := context.WithTimeout(context.Background(), 100*time.Second)
	defer cancel()

	req := pb.SendSingleMsgReq{
		AppId:      msg.AppId,
		SenderId:   msg.SenderId,
		RecieverId: msg.RecieverId,
		Type:       msg.Type,
		Content:    msg.Content,
		SentTime:   msg.SentTime,
		IsLocal:    false,
		Cms:        "cmd",
	}

	mu.RLock()
	//rsp, err := clients[server].SendMsg(context.Background(), &req)
	rsp, err := clients[server].grpcClient.SendSingleChatMsg(ctx, &req)
	mu.RUnlock()

	if err != nil {
		fmt.Println("发送消息", err)

		return
	}

	if rsp.GetRetCode() != common.OK {
		fmt.Println("发送消息", rsp.String())
		err = errors.New(fmt.Sprintf("发送消息失败 code:%d", rsp.GetRetCode()))

		return
	}

	//sendMsgId = rsp.GetSendMsgId()
	//fmt.Println("发送消息 成功:", sendMsgId)

	return
}

// rpc client 发送群聊消息
func SendGroupChatMsg(server string, msg *common.WsGroupChatRequest) (err error) {
	ctx, cancel := context.WithTimeout(context.Background(), 100*time.Second)
	defer cancel()

	req := pb.SendGroupMsgReq{
		AppId:      msg.AppId,
		SenderId:   msg.SenderId,
		RecieverId: msg.RecieverId,
		Type:       msg.Type,
		Content:    msg.Content,
		SentTime:   msg.SentTime,
		IsLocal:    false,
		Cms:        "cmd",
	}

	mu.RLock()
	//rsp, err := clients[server].SendMsg(context.Background(), &req)
	rsp, err := clients[server].grpcClient.SendGroupChatMsg(ctx, &req)
	mu.RUnlock()

	if err != nil {
		fmt.Println("发送消息", err)

		return
	}

	if rsp.GetRetCode() != common.OK {
		fmt.Println("发送消息", rsp.String())
		err = errors.New(fmt.Sprintf("发送消息失败 code:%d", rsp.GetRetCode()))

		return
	}

	//sendMsgId = rsp.GetSendMsgId()
	//fmt.Println("发送消息 成功:", sendMsgId)

	return
}
